<?php
namespace Demo\App\Listener\Pos;

use Swork\Bean\Annotation\Controller;
use Swork\Bean\Annotation\Middleware;
use Swork\Bean\Annotation\TimerTask;
use Swork\Bean\BeanCollector;
use Swork\Configer;
use Swork\Helper\TcpHelper;
use Swork\Middleware\DefaultTcpPushMiddleware;
use Swork\Server\Connection;
use Swork\Server\Tcp\TcpArgument;
use Swork\Service;

/**
 * Class LedListener
 * @Controller("/pos/led")
 * @Middleware(DefaultTcpPushMiddleware::class)
 * @package Demo\App\Handler
 */
class LedListener extends BeanCollector
{
    /**
     * TCP连接类型
     * @var string
     */
    private $fdKey = 'led';

    /**
     * 认证连接
     * @param TcpArgument $argument
     * @return array
     */
    public function auth(TcpArgument $argument)
    {
        //获取内容
        $body = $argument->getBody();
        if ($body == '')
        {
            return ['ERR' => 'E04'];
        }

        //提取参数
        if (!preg_match('/^(\w{3})(\w{8})(\w{32})$/', $body, $match))
        {
            return ['ERR' => 'E05'];
        }
        $idf = $match[1];
        $nonce = $match[2];
        $sign = $match[3];

        //签名密钥
        $secret = Configer::get('pos:led:secret');

        //检查签名
        if ($sign != md5($idf . 'LEDAuth' . $nonce . $secret))
        {
            return ['ERR' => 'E09'];
        }

        //记录已经认证通过
        $fd = $argument->getFd();
        Connection::update($fd, [
            'onClose' => static::class,
            'key' => $this->fdKey
        ]);

        //返回
        return ['RES' => 'OK'];
    }

    /**
     * 心跳
     * @param TcpArgument $argument
     * @return array
     */
    public function beat(TcpArgument $argument)
    {
        //检查是否已经认证通过
        if (!$this->checkIsAuth($argument))
        {
            return ['ERR' => 'E09'];
        }

        //更新时间
        $fd = $argument->getFd();
        Connection::update($fd);

        //返回
        return ['RES' => 'OK'];
    }

    /**
     * 当关闭连接时
     * @param int $fd
     */
    public function onClose(int $fd)
    {
        Connection::remove($fd);
    }

    /**
     * 检查是否已经认证通过
     * @param TcpArgument $argument
     * @return bool
     */
    private function checkIsAuth(TcpArgument $argument)
    {
        $fd = $argument->getFd();
        $fds = Connection::getStoredList();
        if (!isset($fds[$fd]))
        {
            return false;
        }
        return true;
    }

    /**
     * @TimerTask(2000)
     */
    public function sendTask()
    {
        $fds = Connection::getStoredList();
        foreach ($fds as $fd => $value)
        {
            //过滤不是自己的
            if ($value['key'] != $this->fdKey)
            {
                continue;
            }

            //组装发送的数据
            $rel = TcpHelper::assemblyContent('Time', microtime(true));

            //向连接发送数据
            Service::$server->send($fd, $rel);
        }
    }
}
